/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package plash.display;

import plash.events.Event;
import plash.events.EventDispatcher;
import plash.geom.Point;
import plash.geom.Rectangle;
import plash.utils.Debug;
import plash.utils.Logger;
import plash.utils.Math;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PImage;

/**
 *
 * @author User
 */
abstract class DisplayObject extends EventDispatcher implements IDrawable
{

    protected String __name = "";
    protected int __x = 0;
    protected int __y = 0;
    protected int __rotation = 0;
    protected int __width = 0;
    protected int __height = 0;
    protected float __alpha = 1.0f;
    protected int __mouseX = 0;
    protected int __mouseY = 0;
    protected float __radiansRotation = 0;
    protected float __scaleX = 1.0f;
    protected float __scaleY = 1.0f;
    protected boolean __visible = true;
    protected boolean __isMasker = false;
    protected boolean __hasMasker = false;
    protected Point __location = new Point();
    protected Rectangle __boundingBox = new Rectangle();
    protected DisplayObject __mask;
    protected DisplayObjectContainer __parent;
    
    protected Stage __stage;
    public PGraphics __painter;
    public PGraphics __maskPainter;

    public DisplayObject()
    {
    }

    public void refresh()
    {
        if(this.getMask() != null)
        {
            this.setMask(this.getMask());
        }
        this.setIsMasker(this.isIsMasker());
    }

    @Override
    public void draw()
    {
        if (__painter == null)
        {
            return;
        }
        dispatchEvent(new Event(Event.ENTER_FRAME));
    }

    public String getName()
    {
        return __name;
    }

    public void setName(String name)
    {
        this.__name = name;
    }

    public int getX()
    {
        return __x;
    }

    public void setX(int x)
    {
        __location.setX(x);
        this.__x = x;
    }

    public int getY()
    {
        return __y;
    }

    public void setY(int y)
    {
        __location.setY(y);
        this.__y = y;
    }

    public int getRotation()
    {
        return __rotation;
    }

    public void setRotation(int rotation)
    {
        this.__rotation = rotation;
        this.__radiansRotation = Math.toRadians(rotation);
    }

    public int getWidth()
    {
        return __width;
//        return (int) (__boundingBox.getWidth() * this.__scaleX);
    }

    public void setWidth(int width)
    {
        this.__width = width;
    }

    public int getHeight()
    {
        return __height;
//        return (int) (__boundingBox.getHeight() * this.__scaleY);
    }

    public void setHeight(int height)
    {
        this.__height = height;
    }

    public float getAlpha()
    {
        if (this.__parent != null)
        {
            return this.__alpha * this.__parent.getAlpha();
        }
        return __alpha;
    }

    public void setAlpha(float alpha)
    {
        this.__alpha = alpha;
    }

    public int getMouseX()
    {
        return this.__stage.mouseX - this.__x;
    }

    public void setMouseX(int mouseX)
    {
        this.__mouseX = mouseX;
    }

    public int getMouseY()
    {
        return this.__stage.mouseY - this.__y;
    }

    public void setMouseY(int mouseY)
    {
        this.__mouseY = mouseY;
    }

    public boolean isVisible()
    {
        return __visible;
    }

    public void setVisible(boolean visible)
    {
        this.__visible = visible;
    }

    public DisplayObjectContainer getParent()
    {
        return __parent;
    }

    public void setParent(DisplayObjectContainer parent)
    {
        this.__parent = parent;
    }
    
    public PGraphics getStagePainter()
    {
        return __painter;
    }

    public PGraphics getPainter()
    {
        if(this.__hasMasker || this.__isMasker)
        {
            _createMaskPainter();
            return __maskPainter;
        }
        return __painter;
    }

    public void setPainter(PGraphics painter)
    {
        this.__painter = painter;
        this.refresh();
    }

    public float getScaleX()
    {
        return __scaleX;
    }

    public void setScaleX(float scaleX)
    {
        this.__scaleX = scaleX;
    }

    public float getScaleY()
    {
        return __scaleY;
    }

    public void setScaleY(float scaleY)
    {
        this.__scaleY = scaleY;
    }

    public Rectangle getBoundingBox()
    {
        return __boundingBox;
    }

    public void setLocation(Point p)
    {
        this.setX(p.getX());
        this.setY(p.getY());
    }

    public void setLocation(int x, int y)
    {
        this.setX(x);
        this.setY(y);
    }

    public Point getLocation()
    {
        __location.setX(__x);
        __location.setY(__y);
        return __location;
    }

    public DisplayObject getMask()
    {
        return __mask;
    }

    public void setMask(DisplayObject mask)
    {
        Logger.log(this.getName() + " SETTING MASK WITH DISPLAY "+mask);
        //remove existing masker
        if (__mask != null)
        {
            __mask.setIsMasker(false);
        }
        __mask = mask;
        __hasMasker = (this.__mask != null);
        
        //Create or nullify masking based on the new one if it is a real object or null sent to turn masking off
        if (__stage == null)
        {
            Logger.log(this.getName() + " NO STAGE FOUND FOR CREATING MASKPAINTER SO RETURN");
            return;
        }

        if (__mask != null)
        {
            boolean succesfullMask = _createMaskPainter();
            this.__mask.setIsMasker(true);
            if(succesfullMask)
            {
                Logger.log(this.getName() + " MASKPAINTER SUCCESS TO BE MASKED");
            }
            else
            {
                Logger.log(this.getName() + " CREATE GRAPHICS NOT READY TO MASKING YET AS STAGE IS NOT YET AVAILABLE");
            }
        }
        else
        {
            Logger.log("NULL MASK SO REMOVE MASKING");
        }
    }

    public PGraphics getMaskPainter()
    {
        return __maskPainter;
    }

    public void setMaskPainter(PGraphics maskPainter)
    {
        this.__maskPainter = maskPainter;
    }

    public void setIsMasker(boolean isMasker)
    {
        this.__isMasker = isMasker;

        if (this.__painter == null)
        {
            return;
        }

        if (!isMasker)
        {
            __maskPainter = null;
        }
        else
        {
            if (this.__maskPainter == null)
            {
                boolean successfulMask = _createMaskPainter();
                if(successfulMask)
                {                    
                    Logger.log(this.getName() + " MASKPAINTER SUCCESS TO BE A MASK");
                }
                else
                {
                    Logger.log(this.getName() + " CREATE GRAPHICS NOT READY TO MASK ANOTHER OBJECT YET AS STAGE IS NOT YET AVAILABLE");
                }
            }
        }
    }

    public boolean isIsMasker()
    {
        return __isMasker;
    }

    public boolean isHasMasker()
    {
        return __hasMasker;
    }

    public void setHasMasker(boolean __hasMasker)
    {
        this.__hasMasker = __hasMasker;
    }

    public Stage getStage()
    {
        return __stage;
    }

    public void setStage(Stage stage)
    {
        this.__stage = stage;
        this.refresh();
    }
    
    protected boolean _createMaskPainter()
    {
        if(__maskPainter != null)
        {
            return true;
        }
        try
        {
            this.__maskPainter = this.__stage.createGraphics(this.__stage.getWidth(), this.__stage.getHeight(), PApplet.JAVA2D);
            return true;
        }
        catch(NullPointerException npe)
        {
            return false;
        }
    }
    
    protected void doMask(PImage src, int[] maskArray)
    {
        if ((src == null) || (maskArray == null))
        {
            if (Debug.debug_enabled)
            {
                Logger.log("IS THE SRC NULL ?? " + (src == null));
                Logger.log("IS THE MASK NULL ?? " + (maskArray == null));
            }
            return;
        }
        src.loadPixels();
        // don't execute if mask image is different size
        if (maskArray.length != src.pixels.length)
        {
            throw new RuntimeException("mask() can only be used with an image that's the same size.");
        }
        for (int i = 0; i < src.pixels.length; i++)
        {
            if (((maskArray[i] >> 24) & 0xFF) == 0x00)
            {
                src.pixels[i] = 0;
            }
        }        
        src.format = PApplet.ARGB;
        src.updatePixels();
    }
}
